<template>
  <a-spin :spinning="state.loading">
    <a-tree
      :tree-data="state.treeData"
      checkable
      show-line
      check-strictly
      :height="400"
      :load-data="handleLoad"
      :checked-keys="{
        checked: Array.from(state.checkedSet),
        halfChecked: Array.from(state.halfCheckedSet),
      }"
      @check="handleCheck"
      :selected-keys="[]"
    >
      <template #title="{ dataRef }">
        <a-space>
          <span>{{ dataRef.title }}</span>
          <status-tag
            :value="dataRef.type"
            :status-list="[
              { text: '菜单', color: 'orange', value: 'menu' },
              { text: '功能', color: 'green', value: 'function' },
              { text: '权限', color: 'blue', value: 'permission' },
            ]"
          ></status-tag>
        </a-space>
      </template>
    </a-tree>
  </a-spin>
</template>
<script lang="ts" setup>
import { onMounted, reactive, watch } from "vue";
import { queryMF, queryPermission, queryRootMenu } from "@/api/system/menu";
import type { TreeProps } from "ant-design-vue";
import type { QueryResult } from "@/api/system/role/typing";
import type { TreeStructure } from "@/api/system/menu/typing";
import StatusTag from "@/components/status-tag/index.vue";
import { queryRelation } from "@/api/system/role";

interface Props {
  /**行数据 */
  model: QueryResult;
}
const props = defineProps<Props>();

const state = reactive({
  loading: false,
  treeData: [] as TreeProps["treeData"],
  checkedSet: new Set<string>(),
  halfCheckedSet: new Set<string>(),
});
/**获取所有根菜单 */
const getRootMenus = async () => {
  state.loading = true;
  const { success, result } = await queryRootMenu();
  state.loading = false;
  if (success) {
    state.treeData = result;
  }
};

/**查询菜单子集 */
const getMenuChild = async (node: TreeStructure, loading = true) => {
  if (loading) state.loading = true;
  const { success, result } = await queryMF(node.key);
  state.loading = false;
  if (success) {
    node.children = result;
    node.query = true;
  }
};

/**查询功能子集 */
const getFnChild = async (node: TreeStructure, loading = true) => {
  if (loading) state.loading = true;
  const { success, result } = await queryPermission(node.key);
  state.loading = false;
  if (success) {
    node.children = result;
    node.query = true;
  }
};

/**加载children */
const handleLoad: TreeProps["loadData"] = async (node) => {
  if (!node.dataRef.query) {
    if (node.dataRef.type == "menu") {
      await getMenuChild(node.dataRef as TreeStructure, false);
    } else if (node.dataRef.type == "function") {
      await getFnChild(node.dataRef as TreeStructure, false);
    }
    if (!node.dataRef.children.length) node.dataRef.isLeaf = true;
  }
};

/**勾选子节点 */
const checkChild = async (node: TreeStructure) => {
  // 非叶子节点
  if (!node.isLeaf) {
    if (node.query) {
      // 已经查询子节点-勾选子节点
      for (const item of node.children) {
        state.checkedSet.add(item.key);
        await checkChild(item);
      }
    } else {
      // 还未查询子节点-查询子节点keys并勾选
      if (node.type == "menu") {
        await getMenuChild(node);
      } else if (node.type == "function") {
        await getFnChild(node);
      }
      await checkChild(node);
    }
  }
};

/**勾选父节点 */
const checkParent = (node: TreeStructure) => {
  if (!node) return;
  // 是否有子节点未勾选
  let flag = false;
  for (const item of node.children) {
    if (!state.checkedSet.has(item.key)) {
      flag = true;
      // 有子节点未勾选，父节点半勾选
      state.checkedSet.delete(node.key);
      state.halfCheckedSet.add(node.key);
      break;
    }
  }
  // 子节点都勾选，父节点也勾选
  if (!flag) {
    state.halfCheckedSet.delete(node.key);
    state.checkedSet.add(node.key);
  }
  // 向上递归
  if (node.parent) checkParent(node.parent);
};

/**取消勾选子节点 */
const unCheckChild = async (node: TreeStructure) => {
  // 非叶子节点
  if (!node.isLeaf) {
    if (node.query) {
      // 已经查询子节点-取消勾选子节点
      for (const item of node.children) {
        state.checkedSet.delete(item.key);
        state.halfCheckedSet.delete(item.key);
        await unCheckChild(item);
      }
    } else {
      // 还未查询子节点-查询子节点keys并取消勾选
      if (node.type == "menu") {
        await getMenuChild(node);
      } else if (node.type == "function") {
        await getFnChild(node);
      }
      await unCheckChild(node);
    }
  }
};

/**取消勾选父节点 */
const unCheckParent = (node: TreeStructure) => {
  if (!node) return;
  // 是否有子节点勾选或者半勾选
  let flag = false;
  for (const item of node.children) {
    if (state.checkedSet.has(item.key) || state.halfCheckedSet.has(item.key)) {
      flag = true;
      // 有子节点勾选或半勾选，父节点半勾选
      state.checkedSet.delete(node.key);
      state.halfCheckedSet.add(node.key);
      break;
    }
  }
  // 没有子节点勾选或半勾选，父节点取消勾选
  if (!flag) {
    state.halfCheckedSet.delete(node.key);
    state.checkedSet.delete(node.key);
  }
  // 向上递归
  if (node.parent) unCheckParent(node.parent);
};

/**点击checkbox */
const handleCheck: TreeProps["onCheck"] = async (_keys, { node, checked }) => {
  const key = node.key as string;
  state.halfCheckedSet.delete(key);
  if (checked) {
    state.checkedSet.add(key);
    await checkChild(node.dataRef as TreeStructure);
    checkParent(node.parent as TreeStructure);
  } else {
    state.checkedSet.delete(key);
    await unCheckChild(node.dataRef as TreeStructure);
    unCheckParent(node.parent as TreeStructure);
  }
};

const query = async () => {
  state.loading = true;
  const { success, result } = await queryRelation(props.model.roleId);
  state.loading = false;
  if (success) {
    state.checkedSet = new Set(result.checkedKeys);
    state.halfCheckedSet = new Set(result.halfCheckedKeys);
  }
};

watch(
  () => props.model,
  (model) => {
    if (model) query();
  },
  { immediate: true }
);
onMounted(getRootMenus);
defineExpose({ state });
</script>
